package tld.test.interpreter
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.describeType;
	
	import tld.test.interpreter.logic.LogicContext;
	import tld.test.interpreter.math.MathContext;
	import tld.test.interpreter.symbols.SymbolsContext;
	
	public class ParserTest extends Sprite implements IContext
	{
		private static const _program0:String =
		<![CDATA[
			
			]]>.toString();
		
		private static const _program1:String =
			<![CDATA[
				(+ 2 3)
				]]>.toString();
		
		private static const _program2:String =
			<![CDATA[
			(- (* 2 3) 7)	
				]]>.toString();
		
		public function ParserTest()
		{
			super();
			if (super.stage) this.init();
			else super.addEventListener(
				Event.ADDED_TO_STAGE, this.init);
		}
		
		private function init(event:Event = null):void
		{
			super.removeEventListener(
				Event.ADDED_TO_STAGE, this.init);
			var evaluator:Evaluator = new Evaluator();
			var context:IContext = 
				new SymbolsContext(new MathContext(
					new LogicContext(new Context(this))));
			var printer:Printer = new Printer(trace);
			var parser:Parser = new Parser();
			trace("started");
			printer.print(
				evaluator.eval(parser, 
					parser.readExpression(_program0), context));
			printer.print(
				evaluator.eval(parser, 
					parser.readExpression(_program1), context));
			printer.print(
				evaluator.eval(parser, 
					parser.readExpression(_program2), context));
			trace("done");
		}
		
		public function getParent():IContext { return null; }
		
		public function getNames():Object
		{
			var names:Object = { };
			for each (var name:XML in
				describeType(this).accessor.(@access == "public").@name)
				names[name] = this[name];
			return names;
		}
		
		public function setParent(context:IContext):IContext
		{
			// no need to implement this
			return null;
		}
		
		public function put(name:String, value:Object = null):void
		{
			this[name] = value;
		}
			
		public function resolve(name:String):Object
		{
			return this[name];
		}
	}
}